/*
 * Copyright (c) 2024 Shenzhen Kaihong Digital Industry Development Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "kh_sle_host.h"
#include "kh_sle_connect.h"
#include "kh_sle_ssap_client.h"
#include "sle_ssap_client_hal.h"
#include "sle_hilog.h"
#include "sle_ssap_config.h"
#include "sle_ssap_client_config.h"
#include "sle_lite_advance_setting.h"
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <cmsis_os2.h>
#include <pthread.h>

#ifndef ServiceCallbackNumFlag
#define ServiceCallbackNumFlag
#define serviceCallbackNum  3
#endif  // ServiceCallbackNumFlag
static bool g_isSsapcServiceInit = false;
static SleSsapcCallbacks* g_ssapcCbs[serviceCallbackNum] = {NULL};
static SleSsapcHalCallbacks* g_SsapcHalCbs = NULL;
static osMutexId_t g_ssapcCbMuxHandle = 0;
static osSemaphoreId_t g_ssapcSemHandle = 0;
static uint32_t SleSsapcTimeOut = 300;
static SleErrorCode g_sleSsapcAsyncRet = SLE_ERR_UNKNOWN;

typedef struct
{
    uint8_t clientId;
    uint16_t connectId;
    ClientFindServiceRes service;
    SleHalErrorCode errCode;
    SleFindStructureCallback callback;
}FindStructArgs;
void DealSleHalFindStructureCallback(FindStructArgs* args)
{
    uint8_t clientId = args->clientId;
    uint16_t connectId = args->connectId;
    ClientFindServiceRes service = args->service;
    SleHalErrorCode errCode = args->errCode;
    args->callback(clientId, connectId, &service, errCode);
    free(args);
}

void OnSleHalFindStructureCallback(uint8_t clientId, uint16_t connectId, const ClientFindServiceRes *service, SleHalErrorCode errCode)
{
    SLE_LOGD("OnSleHalFindStructureCallback");
    SLE_ASSERT_AND_RETURN(service != NULL);
    ClientFindServiceRes serviceCb;
    osThreadAttr_t attr = {
        .priority = osPriorityNormal,
        .stack_size = 1024 * 2,
        .name = "OnSleFindStructureCb",
    };
    memcpy(&serviceCb, service, sizeof(ClientFindServiceRes));
    for(int i = 0; i < serviceCallbackNum; i++) {
        if(g_ssapcCbs[i] != NULL && g_ssapcCbs[i]->OnSleFindStructureCb != NULL) {
            FindStructArgs* threadArgs = malloc(sizeof(FindStructArgs));
            threadArgs->clientId = clientId;
            threadArgs->connectId = connectId;
            threadArgs->service = *service;
            threadArgs->errCode = errCode;
            threadArgs->callback = g_ssapcCbs[i]->OnSleFindStructureCb;
            osThreadId_t pid = osThreadNew((osThreadFunc_t)DealSleHalFindStructureCallback, (void*)threadArgs, &attr);
        }
    }
}

void OnSleHalFindPropertyCallback(uint8_t clientId, uint16_t connectId, ClientFindPropertyRes *property, SleHalErrorCode errCode)
{
    SLE_LOGD("OnSleHalFindPropertyCallback");
    SLE_ASSERT_AND_RETURN(property != NULL);
    ClientFindPropertyRes propertyCb;
    memcpy(&propertyCb, property, sizeof(ClientFindPropertyRes));
    for(int i = 0; i < serviceCallbackNum; i++) {
        if(g_ssapcCbs[i] != NULL && g_ssapcCbs[i]->OnSleFindPropertyCb != NULL) {
            g_ssapcCbs[i]->OnSleFindPropertyCb(clientId, connectId, &propertyCb, errCode);
        }
    }
}

void OnSleHalCompleteFindStructureCallback(uint8_t clientId, uint16_t connectId, ClientFindStructureRes *structureResult, SleHalErrorCode errCode)
{
    SLE_LOGD("OnSleHalCompleteFindStructureCallback clientId = %d, connectId=%d, findType=%s", clientId, connectId, SsapFindTypeStr(structureResult->type));
    SLE_ASSERT_AND_RETURN(structureResult != NULL);
    g_sleSsapcAsyncRet = (SleErrorCode)errCode;
    osSemaphoreRelease(g_ssapcSemHandle);
}

void OnSleHalReceiveReadResponseCallback(uint8_t clientId, uint16_t connectId, ClientHandleValue *readData, SleHalErrorCode errCode)
{
    SLE_LOGD("OnSleHalReceiveReadResponseCallback");
    SLE_ASSERT_AND_RETURN(readData != NULL);
    ClientHandleValue readDataCb;
    memcpy(&readDataCb, readData, sizeof(ClientHandleValue));
    for(int i = 0; i < serviceCallbackNum; i++) {
        if(g_ssapcCbs[i] != NULL && g_ssapcCbs[i]->OnSleReadCfmCb != NULL) {
            g_ssapcCbs[i]->OnSleReadCfmCb(clientId, connectId, &readDataCb, errCode);
        }
    }
}

void OnSleHalReadByUUidCallback(uint8_t clientId, uint16_t connectId, ClientReadByUuidCmpRes *cmpResult, SleHalErrorCode errCode)
{
    SLE_LOGD("OnSleHalReadByUUidCallback, clientId = %d, connectId=%d"
        , clientId, connectId);
    SLE_ASSERT_AND_RETURN(cmpResult != NULL);
    g_sleSsapcAsyncRet = (SleErrorCode)errCode;
    osSemaphoreRelease(g_ssapcSemHandle);
}

void OnSleHalReceiveWriteResponseCallback(uint8_t clientId, uint16_t connectId, ClientWriteRes *writeResult, SleHalErrorCode errCode)
{
#if 0
    SLE_LOGD("OnSleHalReceiveWriteResponseCallback");
#endif
    SLE_ASSERT_AND_RETURN(writeResult != NULL);
    ClientWriteRes writeResultCb;
    memcpy(&writeResultCb, writeResult, sizeof(ClientWriteRes));
    for(int i = 0; i < serviceCallbackNum; i++) {
        if(g_ssapcCbs[i] != NULL && g_ssapcCbs[i]->OnSleWriteCfmCb != NULL) {
            g_ssapcCbs[i]->OnSleWriteCfmCb(clientId, connectId, &writeResultCb, errCode);
        }
    }
}

typedef struct {
        uint8_t clientId;
        uint16_t connectId;
        SsapMtuInfo mtuInfo;
        SleHalErrorCode errCode;
        SleExchangeInfoCallback callback;
}MtuRespArgs;
void DealSleHalReceiveExchangeInfoResponseCallback(void *ptr)
{
    MtuRespArgs *args = (MtuRespArgs *)ptr;
    uint8_t clientId = args->clientId;
    uint16_t connectId = args->connectId;
    SsapMtuInfo mtuInfo = (args->mtuInfo);
    SleHalErrorCode errCode = args->errCode;
    args->callback(clientId, connectId, &mtuInfo, errCode);
    free(ptr);
}

void OnSleHalReceiveExchangeInfoResponseCallback(uint8_t clientId, uint16_t connectId, SsapMtuInfo *param, SleHalErrorCode errCode)
{
    SLE_LOGD("OnSleHalReceiveExchangeInfoResponseCallback");
    SLE_ASSERT_AND_RETURN(param != NULL);
    SetRecomSendDataSizeAdvance(connectId, param->mtuSize);
    SsapMtuInfo paramCb;
    memcpy(&paramCb, param, sizeof(SsapMtuInfo));
    uint16_t data_len = paramCb.mtuSize + DATA_LEN_BIGGER;
    SleHalErrorCode ret = SleConnectHalSetDataLength(connectId, data_len);
    SLE_ASSERT_AND_RETURN_LOG(ret == SLE_HAL_SUCCESS, "SleConnectHalSetDataLength fail(%d)", ret);
    for(int i = 0; i < serviceCallbackNum; i++) {
        if(g_ssapcCbs[i] != NULL && g_ssapcCbs[i]->OnSleExchangeInfoCb != NULL) {
            osThreadAttr_t attr = {
                .priority = osPriorityNormal,
                .stack_size = 1024 * 2,
                .name = "OnSleExchangeInfoCb",
            };
            MtuRespArgs* threadArgs = malloc(sizeof(MtuRespArgs));
            threadArgs->clientId = clientId;
            threadArgs->connectId = connectId;
            threadArgs->mtuInfo = paramCb;
            threadArgs->errCode = errCode;
            threadArgs->callback = g_ssapcCbs[i]->OnSleExchangeInfoCb;
            osThreadId_t pid = osThreadNew((osThreadFunc_t)DealSleHalReceiveExchangeInfoResponseCallback, (void*)threadArgs, &attr);
            if (pid == NULL) {
                SLE_LOGE("g_ssapcCbs[%d]Failed to create thread", i);
                free(threadArgs);
                break;
            }
        }
    }
}

void OnSleHalReceiveNotificationCallback(uint8_t clientId, uint16_t connectId, ClientHandleValue *data, SleHalErrorCode errCode)
{
    SLE_LOGD("OnSleHalReceiveNotificationCallback");
    SLE_ASSERT_AND_RETURN(data != NULL);
    ClientHandleValue dataCb;
    memcpy(&dataCb, data, sizeof(ClientHandleValue));
    for(int i = 0; i < serviceCallbackNum; i++) {
        if(g_ssapcCbs[i] != NULL && g_ssapcCbs[i]->OnSleNotificatedCb != NULL) {
            g_ssapcCbs[i]->OnSleNotificatedCb(clientId, connectId, &dataCb, errCode);
        }
    }
}

void OnSleHalReceiveIndicationCallback(uint8_t clientId, uint16_t connectId, ClientHandleValue *data, SleHalErrorCode errCode)
{
    SLE_LOGD("OnSleHalReceiveIndicationCallback");
    SLE_ASSERT_AND_RETURN(data != NULL);
    ClientHandleValue dataCb;
    memcpy(&dataCb, data, sizeof(ClientHandleValue));
    for(int i = 0; i < serviceCallbackNum; i++) {
        if(g_ssapcCbs[i] != NULL && g_ssapcCbs[i]->OnSleIndicatedCb != NULL) {
            g_ssapcCbs[i]->OnSleIndicatedCb(clientId, connectId, &dataCb, errCode);
        }
    }
}

SleErrorCode InitSleSsapcService(void)
{
    SLE_LOGD("InitSleSsapcService");
    SLE_ASSERT_AND_RETURN_RET(g_isSsapcServiceInit == false, SLE_NO_ERROR);
    SleErrorCode ret = SLE_ERR_UNKNOWN;
    ret = (SleErrorCode)InitSleSsapcHal();
    SLE_ASSERT_AND_RETURN_RET(ret == SLE_NO_ERROR, ret);

    if (g_ssapcCbMuxHandle == 0) {
      osMutexAttr_t attr = {
            .name = "sle_ssapc_mux",
        };
        g_ssapcCbMuxHandle = osMutexNew(&attr);
    }

    if (g_ssapcSemHandle == 0) {
        // osStatus_t uwRet = LOS_BinarySemCreate(1, &g_ssapcSemHandle);
        g_ssapcSemHandle = osSemaphoreNew(1, 0, NULL);
        // SLE_ASSERT_AND_RETURN_RET(uwRet == osOK, SLE_ERR_SYSTEM_WRONG);
    }

    if(g_SsapcHalCbs == NULL) {
        g_SsapcHalCbs = (SleSsapcHalCallbacks*)malloc(sizeof(SleSsapcHalCallbacks));
        SLE_ASSERT_AND_RETURN_RET(g_SsapcHalCbs != NULL, SLE_ERR_SYSTEM_WRONG);
        g_SsapcHalCbs->OnSsapcStructFoundCb = OnSleHalFindStructureCallback;
        g_SsapcHalCbs->OnSsapcPropertyFoundCb = OnSleHalFindPropertyCallback;
        g_SsapcHalCbs->OnSsapcFindStructDoneCb = OnSleHalCompleteFindStructureCallback;
        g_SsapcHalCbs->OnSsapcRecvReadRespCb = OnSleHalReceiveReadResponseCallback;
        g_SsapcHalCbs->OnSsapcReadByUuidCb = OnSleHalReadByUUidCallback;
        g_SsapcHalCbs->OnSsapcRecvWriteRespCb = OnSleHalReceiveWriteResponseCallback;
        g_SsapcHalCbs->OnSsapcRecvExchangeInfoRespCb = OnSleHalReceiveExchangeInfoResponseCallback;
        g_SsapcHalCbs->OnSsapcRecvNotificationCb = OnSleHalReceiveNotificationCallback;
        g_SsapcHalCbs->OnSsapcRecvIndicationCb = OnSleHalReceiveIndicationCallback;

    }
    ret = (SleErrorCode)SleSsapcHalRegisterCallbacks(g_SsapcHalCbs);
    SLE_ASSERT_AND_RETURN_RET(ret == SLE_NO_ERROR, ret);
    g_sleSsapcAsyncRet = SLE_ERR_UNKNOWN;
    g_isSsapcServiceInit = true;
    return ret;
}

SleErrorCode CheckCanOprateSsapc(void)
{
    SLE_ASSERT_AND_RETURN_RET(g_isSsapcServiceInit == true, SLE_ERR_NOT_READY);
    SleDeviceState hostState;
    SleErrorCode ret = GetSleState(&hostState);
    SLE_ASSERT_AND_RETURN_RET(ret == SLE_NO_ERROR, ret);
    SLE_ASSERT_AND_RETURN_RET(hostState == SLE_HOST_STATE_ENABLED, SLE_ERR_STATUS_WRONG);
    return SLE_NO_ERROR;
}

SleErrorCode DeinitSleSsapcService(void)
{
    SLE_LOGD("DeinitSleSsapcService");
    SleErrorCode ret = CheckCanOprateSsapc();
    SLE_ASSERT_AND_RETURN_RET(ret == SLE_NO_ERROR, ret);
    ret = (SleErrorCode)DeinitSleSsapcHal();
    SLE_ASSERT_AND_RETURN_RET(ret == SLE_NO_ERROR, ret);

    osMutexAcquire(g_ssapcCbMuxHandle, 0);
    if (g_ssapcCbMuxHandle == 0) {
        SLE_LOGW("g_ssapcCbMuxHandle is 0");
        return SLE_NO_ERROR;
    }
    osMutexRelease(g_ssapcCbMuxHandle);
    osMutexDelete(g_ssapcCbMuxHandle);
    g_ssapcCbMuxHandle = 0;
    osSemaphoreDelete(g_ssapcSemHandle);
    g_ssapcSemHandle = 0;
    g_sleSsapcAsyncRet = SLE_ERR_UNKNOWN;
    g_isSsapcServiceInit = false;
    return ret;
}

static SleErrorCode CheckSsapClientUuid(const SleUuid *uuid)
{
    if (uuid->len == 0) {
        return SLE_NO_ERROR;
    }
    bool AllZero = true;
    bool AllFF = true;
    for (int i = 0; i < UUID_LEN; ++i) {
        if (uuid->uuid[i] != 0x00) {
            AllZero = false;
        }
        if (uuid->uuid[i] != 0xFF) {
            AllFF = false;
        }
    }
    SLE_ASSERT_AND_RETURN_RET_LOG((!AllZero && !AllFF), SLE_ERR_INVALID_PARAM, "check uuid error!");
    return SLE_NO_ERROR;
}

SleErrorCode AddSspaClient(const SleUuid *appUuid, uint8_t *clientId)
{
    SLE_LOGD("AddSspaClient");
    SLE_ASSERT_AND_RETURN_RET(appUuid != NULL, SLE_ERR_INVALID_PARAM);
    SleErrorCode ret = CheckSsapClientUuid(appUuid);
    SLE_ASSERT_AND_RETURN_RET(ret == SLE_NO_ERROR, SLE_ERR_INVALID_PARAM);
    SLE_ASSERT_AND_RETURN_RET(clientId != NULL, SLE_ERR_INVALID_PARAM);
    ret = CheckCanOprateSsapc();
    SLE_ASSERT_AND_RETURN_RET(ret == SLE_NO_ERROR, ret);
    //TODO: sdk中clientId暂无用处
    *clientId = 0;
    ret = (SleErrorCode)SleSsapcHalAddClient(appUuid, clientId);
    SLE_ASSERT_AND_RETURN_RET(ret == SLE_NO_ERROR, ret);
    return ret;
}

SleErrorCode RemoveClient(uint8_t clientId)
{
    SLE_LOGD("RemoveClient");
    // TODO: sdk优化clientId后进行入参判断
    SleErrorCode ret = CheckCanOprateSsapc();
    SLE_ASSERT_AND_RETURN_RET(ret == SLE_NO_ERROR, ret);
    ret = (SleErrorCode)SleSsapcHalRemoveClient(clientId);
    SLE_ASSERT_AND_RETURN_RET(ret == SLE_NO_ERROR, ret);
    return ret;
}

static SleErrorCode CheckClientFindStructure(const ClientFindStructure *param)
{
    SLE_ASSERT_AND_RETURN_RET_LOG(param->findType >= SSAP_FIND_TYPE_SERVICE_STRUCTURE_TYPE && param->findType <= SSAP_FIND_TYPE_EVENT_TYPE,
        SLE_ERR_INVALID_PARAM, "param client find type error!");
    SLE_ASSERT_AND_RETURN_RET_LOG(param->startHandle <= param->endHandle,
        SLE_ERR_INVALID_PARAM, "param client start handle than end handle error!");
    SleErrorCode ret = CheckSsapClientUuid(&param->uuid);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, SLE_ERR_INVALID_PARAM, "param client uuid error!");
    return SLE_NO_ERROR;
}

SleErrorCode FindSsapStructure(uint8_t clientId, uint16_t connectId, const ClientFindStructure *paramFind)
{
    SLE_LOGD("FindSsapStructure");
    // TODO: sdk优化clientId后进行入参判断
    SLE_ASSERT_AND_RETURN_RET(connectId < SLE_MAX_CONNECT_ID_NUM, SLE_ERR_INVALID_PARAM);
    SLE_ASSERT_AND_RETURN_RET(paramFind != NULL, SLE_ERR_INVALID_PARAM);
    SleErrorCode ret = CheckClientFindStructure(paramFind);
    SLE_ASSERT_AND_RETURN_RET(ret == SLE_NO_ERROR, ret);
    ret = CheckCanOprateSsapc();
    SLE_ASSERT_AND_RETURN_RET(ret == SLE_NO_ERROR, ret);
    ret = CheckIsConnected(connectId);
    SLE_ASSERT_AND_RETURN_RET(ret == SLE_NO_ERROR, ret);
    ret = (SleErrorCode)SleSsapcHalFindStructure(clientId, connectId, paramFind);
    SLE_ASSERT_AND_RETURN_RET(ret == SLE_NO_ERROR, ret);
    osStatus_t uwRet = osSemaphoreAcquire(g_ssapcSemHandle, SleSsapcTimeOut);
    SLE_ASSERT_AND_RETURN_RET(uwRet != osErrorTimeout, SLE_ERR_TIME_OUT);
    ret = g_sleSsapcAsyncRet;
    g_sleSsapcAsyncRet = SLE_ERR_UNKNOWN;
    return ret;
}

static SleErrorCode CheckClientReadReqByUUID(const ClientReadReqByUUID *param)
{
    SLE_ASSERT_AND_RETURN_RET_LOG(param->findType >= SSAP_FIND_TYPE_SERVICE_STRUCTURE_TYPE && param->findType <= SSAP_FIND_TYPE_EVENT_TYPE,
        SLE_ERR_INVALID_PARAM, "param client find type error!");
    SLE_ASSERT_AND_RETURN_RET_LOG(param->startHandle <= param->endHandle,
        SLE_ERR_INVALID_PARAM, "param client start handle than end handle error!");
    SleErrorCode ret = CheckSsapClientUuid(&param->uuid);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, SLE_ERR_INVALID_PARAM, "param client uuid error!");
    return SLE_NO_ERROR;
}

SleErrorCode SendReadReqByUuid(uint8_t clientId, uint16_t connectId, const  ClientReadReqByUUID *paramRead)
{
    SLE_LOGD("SendReadReqByUuid");
    // TODO: sdk优化clientId后进行入参判断
    SLE_ASSERT_AND_RETURN_RET(connectId < SLE_MAX_CONNECT_ID_NUM, SLE_ERR_INVALID_PARAM);
    SLE_ASSERT_AND_RETURN_RET(paramRead != NULL, SLE_ERR_INVALID_PARAM);
    SleErrorCode ret = CheckClientReadReqByUUID(paramRead);
    SLE_ASSERT_AND_RETURN_RET(ret == SLE_NO_ERROR, ret);
    ret = CheckCanOprateSsapc();
    SLE_ASSERT_AND_RETURN_RET(ret == SLE_NO_ERROR, ret);
    ret = CheckIsConnected(connectId);
    SLE_ASSERT_AND_RETURN_RET(ret == SLE_NO_ERROR, ret);
    SLE_ASSERT_AND_RETURN_RET(ret == SLE_NO_ERROR, ret);
    ret = (SleErrorCode)SleSsapcHalReadReqByUuid(clientId, connectId, paramRead);
    SLE_ASSERT_AND_RETURN_RET(ret == SLE_NO_ERROR, ret);
    osStatus_t uwRet = osSemaphoreAcquire(g_ssapcSemHandle, SleSsapcTimeOut);
    SLE_ASSERT_AND_RETURN_RET(uwRet != osErrorTimeout, SLE_ERR_TIME_OUT);
    ret = g_sleSsapcAsyncRet;
    g_sleSsapcAsyncRet = SLE_ERR_UNKNOWN;
    return ret;
}

SleErrorCode SendReadReq(uint8_t clientId, uint16_t connectId, uint16_t handle, SleSsapPropertyType propertyTpye)
{
    SLE_LOGD("SendReadReq");
    // TODO: sdk优化clientId后进行入参判断
    SLE_ASSERT_AND_RETURN_RET(connectId < SLE_MAX_CONNECT_ID_NUM, SLE_ERR_INVALID_PARAM);
    SLE_ASSERT_AND_RETURN_RET_LOG((propertyTpye >= SLE_SSAP_PROPERTY_TYPE && propertyTpye <= SLE_SSAP_DESCRIPTOR_TYPE_RFU) ||
        propertyTpye == SLE_SSAP_DESCRIPTOR_TYPE_CUSTOM, SLE_ERR_INTERNAL_WRONG, "param request type error!");
    SleErrorCode ret = CheckCanOprateSsapc();
    SLE_ASSERT_AND_RETURN_RET(ret == SLE_NO_ERROR, ret);
    ret = CheckIsConnected(connectId);
    SLE_ASSERT_AND_RETURN_RET(ret == SLE_NO_ERROR, ret);
    ret = (SleErrorCode)SleSsapcHalReadReq(clientId, connectId, handle, propertyTpye);
    SLE_ASSERT_AND_RETURN_RET(ret == SLE_NO_ERROR, ret);
    return ret;
}

static SleErrorCode CheckClientWriteParam(const ClientWriteParam *param)
{
    SLE_ASSERT_AND_RETURN_RET_LOG((param->type >= SLE_SSAP_PROPERTY_TYPE && param->type <= SLE_SSAP_DESCRIPTOR_TYPE_RFU) ||
        param->type == SLE_SSAP_DESCRIPTOR_TYPE_CUSTOM, SLE_ERR_INVALID_PARAM, "param client write handle error!");
    SLE_ASSERT_AND_RETURN_RET_LOG(param->dataLength != 0, SLE_ERR_INVALID_PARAM, "param client write data length 0 error!");
    SLE_ASSERT_AND_RETURN_RET_LOG(param->data, SLE_ERR_INVALID_PARAM, "param client write data null error!");
    return SLE_NO_ERROR;
}

SleErrorCode SendWriteReq(uint8_t clientId, uint16_t connectId, const ClientWriteParam *paramWrite)
{
    SLE_LOGD("SendWriteReq");
    // TODO: sdk优化clientId后进行入参判断
    SLE_ASSERT_AND_RETURN_RET(connectId < SLE_MAX_CONNECT_ID_NUM, SLE_ERR_INVALID_PARAM);
    SLE_ASSERT_AND_RETURN_RET(paramWrite != NULL, SLE_ERR_INVALID_PARAM);
    SleErrorCode ret = CheckClientWriteParam(paramWrite);
    SLE_ASSERT_AND_RETURN_RET(ret == SLE_NO_ERROR, ret);
    ret = CheckCanOprateSsapc();
    SLE_ASSERT_AND_RETURN_RET(ret == SLE_NO_ERROR, ret);
    ret = CheckIsConnected(connectId);
    SLE_ASSERT_AND_RETURN_RET(ret == SLE_NO_ERROR, ret);
    ret = (SleErrorCode)SleSsapcHalWriteReq(clientId, connectId, paramWrite);
    SLE_ASSERT_AND_RETURN_RET(ret == SLE_NO_ERROR, ret);
    return ret;
}

SleErrorCode SendWriteCmd(uint8_t clientId, uint16_t connectId, const ClientWriteParam *paramWrite)
{
    SLE_LOGD("SendWriteCmd");
    // TODO: sdk优化clientId后进行入参判断
    SLE_ASSERT_AND_RETURN_RET(connectId < SLE_MAX_CONNECT_ID_NUM, SLE_ERR_INVALID_PARAM);
    SLE_ASSERT_AND_RETURN_RET(paramWrite != NULL, SLE_ERR_INVALID_PARAM);
    SleErrorCode ret = CheckClientWriteParam(paramWrite);
    SLE_ASSERT_AND_RETURN_RET(ret == SLE_NO_ERROR, ret);
    ret = CheckCanOprateSsapc();
    SLE_ASSERT_AND_RETURN_RET(ret == SLE_NO_ERROR, ret);
    ret = CheckIsConnected(connectId);
    SLE_ASSERT_AND_RETURN_RET(ret == SLE_NO_ERROR, ret);
    ret = (SleErrorCode)SleSsapcHalWriteCmd(clientId, connectId, paramWrite);
    SLE_ASSERT_AND_RETURN_RET(ret == SLE_NO_ERROR, ret);
    return ret;
}

SleErrorCode SendExchangeInfoReq(uint8_t clientId, uint16_t connectId, const SsapMtuInfo *paramExchange)
{
    SLE_LOGD("SendExchangeInfoReq");
    // TODO: sdk优化clientId后进行入参判断
    SLE_ASSERT_AND_RETURN_RET(connectId < SLE_MAX_CONNECT_ID_NUM, SLE_ERR_INVALID_PARAM);
    SLE_ASSERT_AND_RETURN_RET(paramExchange != NULL, SLE_ERR_INVALID_PARAM);
    SleErrorCode ret = CheckCanOprateSsapc();
    SLE_ASSERT_AND_RETURN_RET(ret == SLE_NO_ERROR, ret);
    ret = CheckIsConnected(connectId);
    SLE_ASSERT_AND_RETURN_RET(ret == SLE_NO_ERROR, ret);
    ret = (SleErrorCode)SleSsapcHalExchangeInfoReq(clientId, connectId, paramExchange);
    SLE_ASSERT_AND_RETURN_RET(ret == SLE_NO_ERROR, ret);
    return ret;
}

static bool CheckIsRegistered(const SleSsapcCallbacks *ssapcCallbacks)
{
    for(uint8_t i = 0; i < serviceCallbackNum; i++) {
        if (g_ssapcCbs[i] == ssapcCallbacks) {
            return true;
        }
    }
    return false;
}

SleErrorCode RegisterSsapClientCallbacks(SleSsapcCallbacks* ssapcCallbacks)
{
    SLE_LOGD("RegisterSsapClientCallbacks\r\n");
    SLE_ASSERT_AND_RETURN_RET(ssapcCallbacks != NULL, SLE_ERR_INVALID_PARAM);
    SLE_ASSERT_AND_RETURN_RET(g_isSsapcServiceInit == true, SLE_ERR_NOT_READY);
    SLE_ASSERT_AND_RETURN_RET(CheckIsRegistered(ssapcCallbacks) == false, SLE_NO_ERROR);
    SleErrorCode ret = SLE_ERR_UNKNOWN;
    uint8_t count = 0;
    osMutexAcquire(g_ssapcCbMuxHandle, 0);
    for(; count < serviceCallbackNum; count++) {
        if(g_ssapcCbs[count] == NULL) {
            g_ssapcCbs[count] = ssapcCallbacks;
            ret = SLE_NO_ERROR;
            break;
        }
    }
    osMutexRelease(g_ssapcCbMuxHandle);
    SLE_ASSERT_AND_RETURN_RET(count < serviceCallbackNum, SLE_ERR_NO_MEM);
    SLE_ASSERT_AND_RETURN_RET(ret == SLE_NO_ERROR, ret);
    return ret;
}

SleErrorCode UnregisterSsapClientCallbacks(SleSsapcCallbacks* ssapcCallbacks)
{
    SLE_LOGD("UnregisterSsapClientCallbacks");
    SLE_ASSERT_AND_RETURN_RET(ssapcCallbacks != NULL, SLE_ERR_INVALID_PARAM);
    SLE_ASSERT_AND_RETURN_RET(g_isSsapcServiceInit == true, SLE_ERR_NOT_READY);
    SLE_ASSERT_AND_RETURN_RET(CheckIsRegistered(ssapcCallbacks) == true, SLE_NO_ERROR);
    SleErrorCode ret = SLE_ERR_FAILED;
    osMutexAcquire(g_ssapcCbMuxHandle, 0);
    for(uint8_t i = 0; i < serviceCallbackNum; i++) {
        if (g_ssapcCbs[i] == ssapcCallbacks) {
            g_ssapcCbs[i] = NULL;
            ret = SLE_NO_ERROR;
            break;
        }
    }
    osMutexRelease(g_ssapcCbMuxHandle);
    SLE_ASSERT_AND_RETURN_RET(ret == SLE_NO_ERROR, ret);
    return ret;
}
